package org.je.dev;


/**
 * 这个对象没有自动增加数组长度的功能，使用它你必须估计置入其中数据的数量
 * 
 * @author fanyifeng 2013-1-15
 */
class InnerSynMap
{
	final int		arrayLen;
	final Node[]	nodes;
	int				count;
	final int		locksMod;
	final Object[]	locks;

	/**
	 * @param arrLen
	 */
	InnerSynMap(int arrLen) {
		arrayLen = (arrLen < 8 ? 8 : (arrLen > 1000000 ? 1000000 : arrLen));
		count = 0;
		nodes = new Node[arrayLen];
		locksMod = (arrayLen < 16 ? 7 : 15);
		locks = new Object[locksMod + 1];
		for (int i = 0; i <= locksMod; ++i) {
			locks[i] = new Object();
		}
	}

	int size() {
		return count;
	}

	void put(Object key, Object val) {
		int pos = pos(key);
		synchronized (getLock(pos)) //
		{
			Node tem = nodes[pos];
			while( tem != null ) {
				if (eq(key ,tem.key)) {
					tem.val = val;
					return;
				}
				tem = tem.next;
			}
			tem = new Node(key,val);
			tem.next = nodes[pos];
			nodes[pos] = tem;
			++count;
		}
	}

	Object get(Object key) {
		int pos = pos(key);
		if (nodes[pos] == null)
			return null;
		synchronized (getLock(pos)) //
		{
			Node tem = nodes[pos];
			while( tem != null ) {
				if (eq(tem.key ,key)) {
					return tem.val;
				}
				tem = tem.next;
			}
		}
		return null;
	}

	Object remove(Object key) {

		int pos = pos(key);
		if (nodes[pos] == null)
			return null;

		synchronized (getLock(pos))//
		{
			Node tem = nodes[pos];

			if (tem == null)
				return null;

			if (eq(key ,tem.key)) {
				Object rst = tem.val;
				nodes[pos] = tem.next;
				--count;
				return rst;
			}

			Node before = tem;
			tem = tem.next;

			while( tem != null ) //
			{
				if (eq(key ,tem.key)) //
				{
					Object rst = tem.val;
					before.next = tem.next;
					--count;
					return rst;
				}
				before = tem;
				tem = tem.next;
			}
		}
		return null;
	}

	Object getLock(int pos) {
		return locks[pos & locksMod];
	}

	int pos(Object key) {
		if (key == null)
			return 0;
		int h = key.hashCode();
		if (h < 0) {
			h = h & 0x7fffffff;
		}
		return h % nodes.length;
	}

	boolean eq(Object k1, Object k2) {
		if (k1 == k2)
			return true;
		if (k1 == null || k2 == null)
			return false;
		return k1.equals(k2);
	}

	String getDetails() {
		StringBuilder bf = new StringBuilder();
		for (int i = 0; i < nodes.length; ++i) {
			bf.append(i + " : [");
			Node tem = nodes[i];
			while( tem != null ) {
				bf.append(tem.key + ", ");
				tem = tem.next;
			}
			bf.append("]\r\n");
		}
		return bf.toString().trim();
	}

	static class Node
	{
		Node				next;
		public final Object	key;
		public Object		val;

		Node(Object key, Object val) {
			this.key = key;
			this.val = val;
		}
	}
}
